
#include "rsp_def.h"
#include "tile.h"
#include "controller.h"

#include "coid/comm/hash/hashmap.h"


rsp_controller* rsp_controller::current = 0;


////////////////////////////////////////////////////////////////////////////////
rsp_base::rsp_base()
{
    tile = 0;
    bound = 0;
    slot = UMAX;

    foid = fREQUEST_KILL | xOID;
}

////////////////////////////////////////////////////////////////////////////////
rsp_base::~rsp_base()
{
    if(tile)
        tile->del_object(this);
}


////////////////////////////////////////////////////////////////////////////////
//
//
typedef rsp_base* (*rsp_create_object_fn)();
typedef hash_map< charstr, rsp_create_object_fn, hash<token> >  Thashmap;

static Thashmap& hashmap()
{
    static Thashmap m;
    return m;
}

////////////////////////////////////////////////////////////////////////////////
rsp_base* rsp_base::create_object( const token& clsid )
{
    Thashmap& m = hashmap();
    rsp_create_object_fn* fn = m.find_value(clsid);
    if(!fn)  return 0;

    return (*fn)();
}

////////////////////////////////////////////////////////////////////////////////
token rsp_base::register_class( const token& clsid, rsp_base* (*fn)() )
{
    Thashmap& m = hashmap();
    const rsp_create_object_fn* fnr = m.insert_key_value( clsid, fn );
    DASSERT(fnr);
    return clsid;
}

////////////////////////////////////////////////////////////////////////////////
frame_command_buffer& rsp_base::fcb()
{
    frame_command_buffer& cfcb = tile->leading(0);
    *(ushort*)cfcb.add(sizeof(ushort)) = (ushort)slot;
    return cfcb;
}

////////////////////////////////////////////////////////////////////////////////
///Read client commands
/**
    @param nst number of frames in the message
    @param ackstateid frame id acknowledged by the client
    @param pd,pe start and end of the command buffer
    @return nonzero if successful
**/
int rsp_base::read_cmd( uchar nst, uint ackstateid, const uchar* pd, const uchar* pe )
{
    uchar rep = *pd++;

    const ushort* cmdlens = (const ushort*)pd;

    //skip what we already have
    uint s = RSP_SETTINGS.active_frame() - ackstateid;
    uint d = 0;
    uint i;
    for( i=0; i<s && nst>0; ++i ) {
        if( i >= rep ) {
            pd += cmdlens[d++];
            if( pd > pe )  return 0;    //invalid data
            --nst;
        }
    }

    //read to corresponding frames
    for( ; nst>0; ++i )
    {
        if( i >= rep )
        {
            //DASSERT( i-s <= RSPS_SETTINGS._nwaiting_states+1 );
            uints bs = cmdlens[d++];
            if(bs)
            {
                if( pd + bs > pe )  return 0;
                tile->write( this, i-s, pd, bs );
                pd += bs;

                LOG(2) { *TLOG << "recv cmd: " << timefmt(ackstateid+i-RSP_SETTINGS._nleading)
                    << " (" << i << "/" << s << ")" << BINSTREAM_FLUSH; }
            }

            --nst;
        }
    }

    return -1;
}
